package top.hzy520.common.util;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisCommands;

import java.util.Arrays;
import java.util.Collections;

/**
 * @Author: HouZeYu
 * @Description:
 * @Date: Created in 20:44 2018/6/8
 */
@Component
public class RedisUtils {
   /****  初始化redis库存的LUA脚本   ****/
    private static final String STOCK_CACHE_LUA =
            "local stock=KEYS[1]"+
            "local stock_lock=KEYS[2]"+
            "local stock_val=tonumber(ARGV[1])"+
            "local stock_lock_val=tonumber(ARGV[2])"+
            "local is_exists=redis.call(\"EXISTS\",stock)"+
             "if is_exists == 1  then  " +
             "   return  0 "+
             "else "+
                    "redis.call(\"SET\",stock,stock_val)"+
                    "redis.call(\"SET\",stock_lock,stock_lock_val)"+
             "   return  1 "+
             "end";
    private static final Long EXECUTE_SUCCESS =1L ;
    private static final String SET_IF_NOT_EXIST = "NX";
    private static final String SET_WITH_EXPIRE_TIME = "PX";
    private static final String LOCK_SUCCESS = "OK";
    /****库存扣减LUA脚本 返回 0 代表 key不存在 -1 代表库存不足 返回列表表示扣减成功***/
    private static final String REDUCE_STOCK_LUA =
            "local stock=KEYS[1] \n"+
             "local stock_lock=KEYS[2] \n"+
               "local stock_val = tonumber(ARGV[1])\n"+
                  "local stock_lock_val=tonumber(ARGV[2]) \n"+
                     "local is_exists =redis.call(\"EXISTS\",stock) \n"+
                     "if is_exists == 1 then \n"+
                     "local stockChangeAfter = redis.call(\"INCRBY\",stock,stock_val)\n "+
                           "if stockChangeAfter < 0 then \n"+
                           "redis.call(\"DECRBY\",stock,stock_val) \n"+
                           "return -1 \n"+
                     "else \n"+
                     "local stockLockChangeAfter = redis.call(\"INCRBY\",stock_lock,stock_lock_val) \n"+
                     "return {stockChangeAfter,stockLockChangeAfter} \n"+
                     "end "+
                     "else \n"+
                     "return 0 \n"+
                     "end ";
    /***释放分布式锁**/
    private static final String UNLOCK_LUA =
            "if redis.call(\"GET\",KEY[1])==ARGV[1] then \n"+
            "return redis.call(\"DEL\",KEY[1])\n"+
            "else \n"+
            "return 0 \n"+
            "end";
    @Autowired
    private RedisTemplate<String,String> redisTemplate;
  /**
  *@Author: HouZeYu
  *@Description: 初始化库存
  *@Date: 10:19 2018/6/9
  */
    public boolean initSkuStock(String stockKey, String lockStockKey, String stock, String lockStock) {
   Object object= redisTemplate.execute((RedisCallback<Object>) redisConnection->{
          Jedis jedis= (Jedis) redisConnection.getNativeConnection();
        return  jedis.eval(STOCK_CACHE_LUA,Collections.unmodifiableList(Arrays.asList(stockKey,lockStockKey)),Collections.unmodifiableList(Arrays.asList(stock,lockStock)));
     });
   if (EXECUTE_SUCCESS.equals(object)){
       return true;
   }
   return false;
    }
    /**
    *@Author: HouZeYu
    *@Description: 给订单添加分布式锁
    *@Date: 8:29 2018/6/9
    */
    public boolean lockOrder(String lockKey, String lockValue, int timeout) {
    Object result=redisTemplate.execute((RedisCallback<String>) redisConnection -> {
        JedisCommands jedis= (JedisCommands) redisConnection.getNativeConnection();
         return jedis.set(lockKey,lockValue,SET_IF_NOT_EXIST,SET_WITH_EXPIRE_TIME,timeout);
        });
       if (LOCK_SUCCESS.equals(result)){
           return true;
       }
        return false;
    }
    /**
    *@Author: HouZeYu
    *@Description: 扣减库存
    *@Date: 8:56 2018/6/9
    */
    public Object reduceLock(String stockKey, String stockLockKey, String reduceLockCount, String lockStockCount) {
        Object result=redisTemplate.execute((RedisCallback<Object>) redisConnection ->{
             Jedis jedis= (Jedis) redisConnection.getNativeConnection();
             return jedis.eval(REDUCE_STOCK_LUA,Collections.unmodifiableList(Arrays.asList(stockKey,stockLockKey)),Collections.unmodifiableList(Arrays.asList(reduceLockCount,lockStockCount)));
        });
        return result;
    }
   /**
   *@Author: HouZeYu
   *@Description: 释放分布式锁
   *@Date: 10:20 2018/6/9
   */
    public boolean unLockOrder(String lockKey,String lockValue){
        Object result=redisTemplate.execute((RedisCallback<Object>) redisConnection ->{
            Jedis jedis= (Jedis) redisConnection.getNativeConnection();
            return jedis.eval(UNLOCK_LUA,Collections.unmodifiableList(Arrays.asList(lockKey)),Collections.unmodifiableList(Arrays.asList(lockValue)));
        });
        if (EXECUTE_SUCCESS.equals(result)){
            return true;
        }
        return false;
    }
}
